Piano notes book, powered by Astro and React.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 

119 lignes
3.0 KiB

  1. import createVerovioModule from 'verovio/wasm';
  2. import { VerovioToolkit } from 'verovio/esm';
  3. import { readFile, readdir } from 'node:fs/promises';
  4. import { JSDOM } from 'jsdom';
  5. import type {APIRoute, GetStaticPaths} from 'astro';
  6. const filter = (musicXml: string) => {
  7. const jsdom = new JSDOM(musicXml, { pretendToBeVisual: true, contentType: 'image/svg+xml' });
  8. const win = jsdom.window;
  9. // const win = jsdom.window;
  10. return win.document.documentElement.outerHTML;
  11. };
  12. const processOutput = (xmlData: string) => {
  13. const jsdom = new JSDOM(xmlData, { pretendToBeVisual: true, contentType: 'image/svg+xml' });
  14. const win = jsdom.window;
  15. const [svgElemsRoot, svgElemsMain] = Array.from(win.document.getElementsByTagName('svg'));
  16. if (typeof svgElemsRoot === 'undefined') {
  17. return '';
  18. }
  19. if (typeof svgElemsMain === 'undefined') {
  20. return '';
  21. }
  22. // svgElemsRoot.getAttributeNames().forEach((a) => {
  23. // const attr = svgElemsRoot.getAttribute(a);
  24. // if (!attr) {
  25. // return;
  26. // }
  27. // svgElemsMain.setAttribute(a, attr);
  28. // });
  29. Array.from(svgElemsRoot.children).forEach((h) => {
  30. if (h !== svgElemsMain) {
  31. h.remove();
  32. if (h.tagName.toLowerCase() === 'desc') {
  33. return;
  34. }
  35. if (svgElemsMain.children[0]) {
  36. svgElemsMain.insertBefore(h, svgElemsMain.children[0]);
  37. return;
  38. }
  39. svgElemsMain.appendChild(h);
  40. }
  41. });
  42. Array.from(win.document.getElementsByClassName('pgHead')).forEach(h => {
  43. h.remove();
  44. });
  45. Array.from(win.document.getElementsByClassName('pgFoot')).forEach(h => {
  46. h.remove();
  47. });
  48. Array.from(win.document.getElementsByTagName('defs')).forEach(h => {
  49. h.remove();
  50. if (svgElemsMain) {
  51. if (svgElemsMain.children[0]) {
  52. svgElemsMain.insertBefore(h, svgElemsMain.children[0]);
  53. } else {
  54. svgElemsMain.appendChild(h);
  55. }
  56. }
  57. });
  58. return `<?xml version="1.0" encoding="utf-8"?>${svgElemsMain.outerHTML}`
  59. };
  60. export const GET: APIRoute = async ({ params }) => {
  61. console.log('asdfasdf');
  62. const verovioModule = await createVerovioModule();
  63. const score = await readFile(`public/scores/${params.asset}.musicxml`, 'utf-8');
  64. const verovioToolkit = new VerovioToolkit(verovioModule);
  65. const filteredScore = filter(score);
  66. const isSuccessful = verovioToolkit.loadData(filteredScore);
  67. if (!isSuccessful) {
  68. return new Response(null, { status: 500 });
  69. }
  70. verovioToolkit.setOptions({
  71. breaks: 'none',
  72. font: 'Bravura',
  73. });
  74. let data: string;
  75. try {
  76. const raw = verovioToolkit.renderToSVG(1)
  77. .replace(/xmlns:mei="(.+?)"/g, '')
  78. .replace(/xlink:/g, '');
  79. data = processOutput(raw);
  80. } catch (err) {
  81. console.error(err);
  82. return new Response(null, { status: 500 });
  83. }
  84. return new Response(
  85. data,
  86. {
  87. headers: {
  88. 'Content-Type': 'image/svg+xml',
  89. },
  90. status: 200,
  91. }
  92. );
  93. };
  94. export const getStaticPaths: GetStaticPaths = async () => {
  95. const files = await readdir('public/scores');
  96. return files
  97. .filter((f) => f.endsWith('.musicxml'))
  98. .map((f) => ({
  99. params: {
  100. asset: f.replace(/\.musicxml/g, ''),
  101. },
  102. }));
  103. };